<template>
  <div
    class="dropdownbox"
    :class="{ clicked: show }"
    @click.stop="clicked"
    ref="container"
  >
    <!-- 内容显示 -->
    <span class="content">sdfsdfsdfsd</span>
    <i :show="show" class="mu-icon-down icon"></i>
    <!-- 显示的列表 -->
    <div
      @click.stop
      :direction="direction"
      class="list position"
      :class="{ show }"
      ref="list"
    >
      <!-- 头部 -->
      <header>
        <!-- 中间部分 -->
        <div class="center">
          <span
            @click="headerClickHandler(item, index)"
            v-for="(item, index) in title"
            :key="index"
            >{{ item }}
          </span>
        </div>
        <!-- 左边部分 -->
        <div class="left">
          <i
            class="mu-icon-shuangjiantou-zuo"
            @click="arrowClickHandler(false, true)"
          ></i>
          <i
            v-if="mode === 'date'"
            class="mu-icon-arrow-left"
            @click="arrowClickHandler(false, false)"
          ></i>
        </div>
        <!-- 右边部分 -->
        <div class="right">
          <i
            v-if="mode === 'date'"
            class="mu-icon-arrow-left"
            @click="arrowClickHandler(true, false)"
          ></i>
          <i
            class="mu-icon-shuangjiantou-you"
            @click="arrowClickHandler(true, true)"
          ></i>
        </div>
      </header>
      <!-- 日期列表 -->
      <table cellpadding="0" cellspacing="0">
        <!-- 日期列表头部 -->
        <thead>
          <tr>
            <th v-for="(item, index) in theader" :key="index">
              {{ item }}
            </th>
          </tr>
        </thead>
        <!-- 日期列表中间部分 -->
        <tbody>
          <tr v-for="(children, index) in dateList" :key="index">
            <td
              @click="select(item)"
              v-for="(item, cIndex) in children"
              :key="cIndex"
              :otherMonth="item.otherMonth"
              :selected="
                mode === 'date'
                  ? item.date.valueOf() === date.valueOf()
                  : item.date.getFullYear() === date.getFullYear() &&
                    item.date.getMonth() === date.getMonth()
              "
            >
              <span>
                {{ item.text }}
              </span>
            </td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>
</template>

<script>
import {
  addEventListener,
  removeEventListener,
  findOffsetTop,
} from "../utils/events";
const weeks = ["日", "一", "二", "三", "四", "五", "六"];
export default {
  name: "mu-date-picker",
  data() {
    return {
      // 中文月
      chineseMonths: [
        "一",
        "二",
        "三",
        "四",
        "五",
        "六",
        "七",
        "八",
        "九",
        "十",
        "十一",
        "十二",
      ],
      theader: [], //星期
      title: [],
      date: new Date(), //选中的日期
      start: new Date(), //起始日期
      show: false, //是否显示
      direction: "", //向上
      dateList: [], //日期列表
      mode: "date", //模式，date,year,month
    };
  },
  computed: {
    // 选年范围
    yearRange() {
      const first = this.dateList[0][0];
      let last = this.dateList[this.dateList.length - 1];
      last = last[last.length - 1];
      return `${first.date} 年 - ${last.date} 年`;
    },
  },
  created() {
    this.start = new Date(
      this.start.getFullYear(),
      this.start.getMonth(),
      this.start.getDate()
    );
    this.date = new Date(this.start.valueOf());
    this.calcDate();
  },
  mounted() {
    this.setDirection();
    addEventListener(document, "click", this.hide);
  },
  beforeDestroy() {
    removeEventListener(document, "click", this.hide);
  },
  methods: {
    // 箭头处理
    arrowClickHandler(add, double) {
      switch (this.mode) {
        case "date":
          if (double) {
            this.start.setFullYear(this.start.getFullYear() + (add ? 1 : -1));
          } else {
            this.start.setMonth(this.start.getMonth() + (add ? 1 : -1));
          }
          this.calcDate();
          break;
        case "year":
          this.start.setFullYear(this.start.getFullYear() + (add ? 12 : -12));
          this.calcYears();
          break;
        case "month":
          this.start.setFullYear(this.start.getFullYear() + (add ? 1 : -1));
          this.initMonth();
          break;
      }
    },
    // 头部点击处理器
    headerClickHandler(item, index) {
      if (index === 0) {
        switch (this.mode) {
          // 选中的年
          case "date":
            this.initYear();
          case "month":
            this.initYear();
            break;
        }
      } else {
        // 选中的是月份
        this.initMonth();
      }
    },
    // 选中
    select(item) {
      this.start = new Date(item.date.valueOf());
      switch (this.mode) {
        case "year":
          this.initMonth();
          break;
        case "month":
          this.calcDate();
          break;
        case "date":
          this.date = new Date(item.date.valueOf());
          this.show = false;
          break;
      }
    },
    // 初始化月
    initMonth() {
      this.title.splice(0, Infinity, `${this.start.getFullYear()} 年`);
      this.theader.splice(0, Infinity, ...new Array(4));
      this.dateList.splice(0, Infinity);
      this.chineseMonths.forEach((date, index) => {
        if (index % 4 === 0) {
          this.dateList.push([]);
        }
        this.dateList[this.dateList.length - 1].push({
          date: new Date(this.start.getFullYear(), index, 1),
          text: date + "月",
        });
      });
      this.mode = "month";
    },
    // 初始化年
    initYear() {
      this.theader.splice(0, Infinity, ...new Array(4));
      const year = this.start.getFullYear();
      this.start.setFullYear(year - (year % 10));
      this.calcYears();
      this.mode = "year";
    },
    // 计算年
    calcYears() {
      const start = new Date(this.start.valueOf());
      const end = new Date(start.valueOf());
      end.setFullYear(start.getFullYear() + 11);
      this.title.splice(
        0,
        Infinity,
        `${this.start.getFullYear()} 年 - ${end.getFullYear()} 年`
      );
      this.dateList.splice(0, Infinity);
      let index = 0;
      while (start <= end) {
        if (index++ % 4 === 0) {
          this.dateList.push([]);
        }
        this.dateList[this.dateList.length - 1].push({
          text: start.getFullYear(),
          date: new Date(start.valueOf()),
        });
        start.setFullYear(start.getFullYear() + 1);
      }
    },
    // 改变年
    changeYear(years) {
      this.date.setFullYear(this.date.getFullYear() + years);
      this.calcYears(this.dateList[0][0].date + years);
    },
    // 计算日期
    calcDate() {
      // 生成周几
      this.theader.splice(0, Infinity, ...weeks);
      // 生成标题
      this.title.splice(
        0,
        Infinity,
        this.start.getFullYear() + " 年",
        this.start.getMonth() + 1 + " 月"
      );
      const date = new Date(this.start.valueOf());
      date.setDate(1); //设置月初
      const month = date.getMonth(); //当前月
      const weekday = date.getDay(); //获取周几
      // 如果不是周日
      if (weekday !== 0) {
        date.setDate(date.getDate() - weekday); //与周日相差几天，往前推
      }
      const endDate = new Date(date.valueOf()); //复制开始日期
      endDate.setDate(date.getDate() + 41);
      // 生成日期
      this.dateList.splice(0, Infinity);
      while (date <= endDate) {
        if (date.getDay() === 0) {
          this.dateList.push([]);
        }
        this.dateList[this.dateList.length - 1].push({
          date: new Date(date.valueOf()),
          otherMonth: date.getMonth() !== month,
          text: date.getDate(),
        });
        date.setDate(date.getDate() + 1);
      }
      this.mode = "date";
    },
    //隐藏方法
    hide(e) {
      this.show = false;
    },
    //点击显示或隐藏
    clicked() {
      this.setDirection();
      this.show = !this.show;
    },
    //设置方向
    setDirection() {
      const top =
        findOffsetTop(this.$refs.container.parentElement, 0) +
        this.$refs.container.offsetTop +
        this.$refs.container.offsetHeight +
        this.$refs.list.clientHeight +
        20 -
        document.documentElement.scrollTop;
      this.direction =
        top > document.documentElement.clientHeight ? "top" : "bottom";
    },
  },
  props: {},
};
</script>
<style lang="scss" scoped>
@import "../variable.scss";

.clicked {
  border: $blue 1px solid !important;
}

.dropdownbox {
  position: relative;
  display: inline-block;
  border: $gray 1px solid;
  transition: 0.3s;
  padding: 5px;
  font-size: 13px;
  border-radius: 3px;

  .content {
    padding: 0px 20px;
  }

  &:hover {
    border: $blue 1px solid;
  }

  .list {
    background: #ffffff;
    margin: 0;
    list-style: none;
    position: absolute;
    padding: 5px 0;
    left: 0;
    transform: scaleY(0);
    border-radius: 3px;
    box-shadow: 0 0 10px $gray;
    opacity: 0;
    transition: transform 0.2s ease-in, opacity 0.2s ease-in;
    padding-top: 20px;

    header {
      font-size: 22px;
      overflow: hidden;
      padding-bottom: 10px;

      .left {
        float: left;
        margin-left: -100%;
        padding-left: 20px;

        .double {
          letter-spacing: -10px;
        }

        .single {
          padding-left: 10px;
        }
      }

      .right {
        float: right;
        padding-right: 20px;
        text-align: right;
        margin-left: -100px;

        .mu-icon-arrow-left {
          transform: rotate(180deg);
        }
      }

      .center {
        font-size: 16px;
        float: left;
        width: 100%;
        text-align: center;

        span {
          padding: 0 5px;
        }
      }

      span,
      i {
        cursor: pointer;

        &:hover {
          color: $blue;
        }
      }
    }

    table {
      margin: 0 20px;

      th {
        user-select: none;
        padding: 10px 0;
        font-weight: normal;
        border-bottom: 1px solid #dfdcdc;
      }

      tbody {
        td {
          padding: 15px 13px;
          cursor: pointer;
          white-space: nowrap;
          word-break: normal;

          &[otherMonth] {
            color: #c0c4cc;

            &:hover {
              color: #c0c4cc;
            }
          }

          &[selected] {
            color: $blue;
          }

          &:hover {
            color: $blue;
          }
        }
      }

      td,
      th {
        text-align: center;
        vertical-align: middle;
      }
    }
  }

  .list[direction="bottom"] {
    transform-origin: 0 0;
  }

  .list[direction="top"] {
    transform-origin: 0 100%;
  }

  .position[direction="top"] {
    bottom: 35px;

    &:before {
      box-sizing: content-box;
      width: 0px;
      height: 0px;
      position: absolute;
      bottom: -10px;
      left: 21px;
      padding: 0;
      border-bottom: 5px solid transparent;
      border-top: 5px solid #ffffff;
      border-left: 5px solid transparent;
      border-right: 5px solid transparent;
      display: block;
      content: "";
      z-index: 12;
    }

    &:after {
      box-sizing: content-box;
      width: 0px;
      height: 0px;
      position: absolute;
      bottom: -12px;
      left: 20px;
      padding: 0;
      border-bottom: 6px solid transparent;
      border-top: 6px solid $gray;
      border-left: 6px solid transparent;
      border-right: 6px solid transparent;
      display: block;
      content: "";
      z-index: 10;
    }
  }

  .position[direction="bottom"] {
    top: 33px;

    &:before {
      box-sizing: content-box;
      width: 0px;
      height: 0px;
      position: absolute;
      top: -10px;
      left: 21px;
      padding: 0;
      border-bottom: 5px solid #ffffff;
      border-top: 5px solid transparent;
      border-left: 5px solid transparent;
      border-right: 5px solid transparent;
      display: block;
      content: "";
      z-index: 12;
    }

    &:after {
      box-sizing: content-box;
      width: 0px;
      height: 0px;
      position: absolute;
      top: -12px;
      left: 20px;
      padding: 0;
      border-bottom: 6px solid $gray;
      border-top: 6px solid transparent;
      border-left: 6px solid transparent;
      border-right: 6px solid transparent;
      display: block;
      content: "";
      z-index: 10;
    }
  }

  .show {
    transform: scaleY(1);
    opacity: 1;
  }

  .icon {
    color: #cccccc;
    transition: transform 0.3s;
  }

  .icon[show] {
    transform: rotate(-180deg);
  }
}
</style>